library(rgl)
knitr::knit_hooks$set(webgl = hook_webgl)

Scalable Vector Graphics, abbreviated: SVG, is an XML-based file format for static and dynamic vector graphics. It is an open standard of the W3C. Inkscape is an open source vector illustration program that uses the SVG format to store vector graphics. We start our analyses from checking Inkscape installation

This is the Scalable Vector Graphic we want to analyze:

url <- 'https://upload.wikimedia.org/wikipedia/commons/1/1b/Red_Bird.svg'
knitr::include_graphics(url)

As far there is no easy way to import SVG file, convert it into Simple Features and analyze using R. That’s why we gonna use an external powerful and beautiful tool which is Inkscape.

system('inkscape --version', intern = TRUE)
## [1] "Inkscape 1.2.1 (9c6d41e410, 2022-07-14)"

Simple Features from SVG

We can use dedicated R package https://github.com/JacekPardyak/inkscaper.

devtools::install_github("JacekPardyak/inkscaper")
## Skipping install of 'inkscaper' from a github remote, the SHA1 (281ef70f) has not changed since last install.
##   Use `force = TRUE` to force installation
library(inkscaper)

Function to convert SVG into SF

logo <- url %>% 
  inx_svg2sf() %>%
  select(geometry) %>%
  st_union() %>%
  st_polygonize() %>% 
  first()
## Reading layer `entities' from data source 
##   `C:\Users\jacek\AppData\Local\Temp\Rtmp8eyASy\inx_3ac41623293.dxf' 
##   using driver `DXF'
## Simple feature collection with 2797 features and 6 fields
## Geometry type: LINESTRING
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
logo %>% ggplot() +
  geom_sf()

result <- st_sfc() %>% st_sf(geometry = .)

for(i in c(1: length(logo))) {
  tmp <- logo %>% 
  nth(i) %>%
  st_sfc()  %>% st_sf(geometry = .) %>% mutate(facet = i)
  result <- tmp %>% bind_rows(result) 
}
result %>% ggplot() +
  geom_sf() +
  geom_sf_label(aes(label = facet)) +
  theme_void()

result %>% plot_ly(split = ~facet)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
result %>% st_write("Red_Bird.shp", append=FALSE)
## Deleting layer `Red_Bird' using driver `ESRI Shapefile'
## Writing layer `Red_Bird' to data source `Red_Bird.shp' using driver `ESRI Shapefile'
## Writing 92 features with 1 fields and geometry type Polygon.
logo <- st_read("./Red_Bird.shp") %>% filter(!facet %in% 
                    c(3:55, 56:60, 81)) %>% st_union()
## Reading layer `Red_Bird' from data source 
##   `C:\Users\jacek\OneDrive\Documents\JacekPardyak.github.io\inkscaper\Red_Bird.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 92 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
logo %>% ggplot() +
  geom_sf() +
  theme_void()

Surface from SVG

result <- st_read("./Red_Bird.shp") %>% filter(!facet %in% 
                    c(3:55, 56:60, 81)) %>% st_union() %>% st_sfc() %>% st_sf()
## Reading layer `Red_Bird' from data source 
##   `C:\Users\jacek\OneDrive\Documents\JacekPardyak.github.io\inkscaper\Red_Bird.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 92 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
result
## Simple feature collection with 1 feature and 0 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
##                         geometry
## 1 MULTIPOLYGON (((55.96632 7....
result %>% ggplot() +
  geom_sf()

result
## Simple feature collection with 1 feature and 0 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
##                         geometry
## 1 MULTIPOLYGON (((55.96632 7....
grid_spacing = 1
grid <- result %>% st_make_grid(what = "centers", cellsize = c(grid_spacing, grid_spacing)) %>%
  st_sf() 
heights <- st_join(grid, (result %>% select(geometry) %>% mutate(Z = 1))) %>% replace(is.na(.), 0) 
z <- heights %>% st_coordinates() %>% as_tibble() %>% 
  bind_cols(heights %>% st_drop_geometry()) %>%
  mutate(X = round(X,1)) %>%
  mutate(Y = round(Y,1)) %>% pivot_wider(names_from = Y, values_from = Z) %>%
  column_to_rownames("X") %>% as.matrix()
x <- 1:nrow(z)  
y <- 1:ncol(z)  

colorlut <- c("#F2F2F2",  "#E34234") #"#ECB176",
col <- colorlut[ z - min(z) + 1 ] # assign colors to heights for each point

#open3d()
surface3d(x, y, z, color = col, back = "lines")

#e34234
#close3d()

Animation from SVG

library(gganimate)

result_1 <- st_read("./Red_Bird.shp") %>% filter(!facet %in% 
                    c(3:55, 56:60, 81)) %>% st_union() %>% st_sfc() %>% st_sf() %>% 
  mutate(facet = 1)
## Reading layer `Red_Bird' from data source 
##   `C:\Users\jacek\OneDrive\Documents\JacekPardyak.github.io\inkscaper\Red_Bird.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 92 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
result_2 <- st_read("./Red_Bird.shp") %>% filter(facet %in% 
                    c(3:55, 56:60, 81)) %>% st_union() %>% st_sfc() %>% st_sf() %>% 
  mutate(facet = 2)
## Reading layer `Red_Bird' from data source 
##   `C:\Users\jacek\OneDrive\Documents\JacekPardyak.github.io\inkscaper\Red_Bird.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 92 features and 1 field
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 22.41016 ymin: 5.324796 xmax: 103.6297 ymax: 87.57702
## CRS:           NA
result <- result_1 %>% bind_rows(result_2)
result %>% ggplot() +
  geom_sf()  + 
  transition_states(
    facet,
    transition_length = 2,
    state_length = 1
  ) +
  enter_fade() + 
  exit_shrink() +
  ease_aes('sine-in-out')

Appendix A - Inkscape Actions

While obviously Inkscape is primarily intended as a GUI application, it can be used for doing SVG processing on the command line as well. Inkscape Actions available in versions Inkscape 1.2.1 (9c6d41e410, 2022-07-14) are listed below.

Appendix B - Inkscape Extensions

Inkscape Extensions are small programs that extend Inkscape’s functionality. They can provide features for specific tasks, experimentation, or art styles. They can also add support for special hardware or different export formats. While many extensions are included with Inkscape, you can also install extensions written by third parties or write your own. The table below shows the list of extensions available in Inkscape of version Inkscape 1.2.1 (9c6d41e410, 2022-07-14) with descriptions.